﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;
using System.IO;

namespace Billing
{
    public class CryptoUtils
    {
        private static string RSAXmlKey
        {
            get
            {
                return "<RSAKeyValue>"
                        + "<Modulus>p34iAT8yvPcbpr66H0aycnYZMWf6mFulJkS5VE/kc2Jvk/jeTlQ/mSt+YcaWfbFx36Sx0lzUJNDhv6sXxDvVVyAI3IpqpB645Xsafco20Baf1yL8GKIEQKth+Soaw87FVqbdGVB0GYORUyzZTSksqILDDTicz/EO5/X8Nt4a3SM=</Modulus>"
                        + "<Exponent>AQAB</Exponent>"
                        + "<P>33wQnEwp+3F4F4RMYLrLCEqKQYPL2abB/AKDLLVUaajGZYV4VZCLM681oXcADMiCj4Cn+Blg/PuGqkK+JVlVqQ==</P>"
                        + "<Q>v9yWDVzPR4TAJxGGqzy8a8mWA+7n+J7ps0YIuWbKy21U/NfsdUp6bVZyRcPubKOcXxLBW0hMCczJ15RNRv5D6w==</Q>"
                        + "<DP>c7y4jXkUNNeqreMh+uZBx2Vy/ELZCzrFM1HJxRmTQbTaKjFZBFb7ACU4zQnnyLb+hnrGgkICbIGGWB6Agq8lIQ==</DP>"
                        + "<DQ>qTDb/gKnI3l0fb9d06mmuyK0sNlAJSX2DsqmrOBx2zyZ4rKC6df46GyALveeTJ1nKwv+CQJTU50NLZexIfbdaw==</DQ>"
                        + "<InverseQ>UO0rIlSMsOWcyj/ZA4v4e2DHcvP21ejztxOwRWJ+fdZwW2Mfze2XVfCVUOMDGHw8FMoW4u4e4VuD3BZyCUTDgQ==</InverseQ>"
                        + "<D>R4ixUUMCkn4fSynuJ+lz0TrrK5SzDFsnv55eYMn2UelaqiICIAYPW4Wd5niAUZJ1hgS7BZMr78VehRO3hNHhHTFnELu7OxO8o2xTZPD36jex4Bnh0jJ/vPWmjmoZ2YbhtjhdKmZcqId7C10idGIvoxKs/hyrExBnscujDFj8AmE=</D>"
                        + "</RSAKeyValue>";
            }
        }

        public static string CreateMD5(string input)
        {
            if (string.IsNullOrEmpty(input))
                input = string.Empty;
            MD5 md5Hasher = MD5.Create();
            byte[] data = md5Hasher.ComputeHash(Encoding.Default.GetBytes(input));
            StringBuilder sBuilder = new StringBuilder();

            for (int i = 0; i < data.Length; i++)
            {
                sBuilder.Append(data[i].ToString("x2"));
            }
            return sBuilder.ToString();
        }

        public string GetMD5(string input)
        {
            return CryptoUtils.CreateMD5(input);
        }

        /// <summary>
        /// encrypts input by RSA algorithm using inner consant key
        /// </summary>
        /// <param name="DataToEncrypt">data to encrypt</param>
        /// <returns>returns base64 string</returns>
        public static string RSAEncrypt(string DataToEncrypt)
        {
            return Convert.ToBase64String(RSAEncrypt(Encoding.UTF8.GetBytes(DataToEncrypt)));
        }

        /// <summary>
        /// decrypts input by RSA algorith using inner constan key
        /// </summary>
        /// <param name="DataToDecrypt_Base64">data to decrypt represented by Base64 string</param>
        /// <returns>returs decrypted string</returns>
        public static string RSADecrypt(string DataToDecrypt_Base64)
        {
            return Encoding.UTF8.GetString(RSADecrypt(Convert.FromBase64String(DataToDecrypt_Base64)));
        }

        public static byte[] RSAEncrypt(byte[] DataToEncrypt)
        {
            RSAParameters RSAKeyInfo = GetKeyInfoFromXMLString(RSAXmlKey, false);

            return RSAEncrypt(DataToEncrypt, RSAKeyInfo, false);
        }

        public static byte[] RSADecrypt(byte[] DataToDecrypt)
        {
            RSAParameters RSAKeyInfo = GetKeyInfoFromXMLString(RSAXmlKey, true);

            return RSADecrypt(DataToDecrypt, RSAKeyInfo, false);
        }

        public static byte[] RSAEncrypt(byte[] DataToEncrypt, string keyXmlFilePath)
        {
            RSAParameters RSAKeyInfo = GetKeyInfoFromFile(keyXmlFilePath, false);

            return RSAEncrypt(DataToEncrypt, RSAKeyInfo, false);
        }

        public static byte[] RSADecrypt(byte[] DataToDecrypt, string keyXmlFilePath)
        {
            RSAParameters RSAKeyInfo = GetKeyInfoFromFile(keyXmlFilePath, true);

            return RSADecrypt(DataToDecrypt, RSAKeyInfo, false);
        }

        public static byte[] RSAEncrypt(byte[] DataToEncrypt, RSAParameters RSAKeyInfo, bool DoOAEPPadding)
        {
            RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
            RSA.ImportParameters(RSAKeyInfo);
            return RSA.Encrypt(DataToEncrypt, DoOAEPPadding);
        }

        public static byte[] RSADecrypt(byte[] DataToDecrypt, RSAParameters RSAKeyInfo, bool DoOAEPPadding)
        {
            RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
            RSA.ImportParameters(RSAKeyInfo);
            return RSA.Decrypt(DataToDecrypt, DoOAEPPadding);
        }

        private static RSAParameters GetKeyInfoFromFile(string keyXmlFilePath, bool includePrivateKey)
        {
            if (!File.Exists(keyXmlFilePath))
                throw new BillingSystemException("RSA Key file not found");

            string xmlKeyValue = File.OpenText(keyXmlFilePath).ReadToEnd();
            return GetKeyInfoFromXMLString(xmlKeyValue, includePrivateKey);


        }

        private static RSAParameters GetKeyInfoFromXMLString(string xmlKeyValue, bool includePrivateKey)
        {
            RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
            RSA.FromXmlString(xmlKeyValue);
            return RSA.ExportParameters(includePrivateKey);
        }
    }
}